package hivMultiCompartment;

import hivMultiCompartment.TCell.AgentState;

import java.util.ArrayList;
import java.util.Iterator;

public class APCell extends Cell implements SusceptibleCell{
	
	public enum AgentState{
		IMMATURE, MATURE
	}
	
	public AgentState state;
	public boolean CD4Positive;
	public double reactivationRate;
	public boolean infected;
	public Virus bearingVirus;
	
	public APCell() {
		super ();
		
		avgLife = GlobalConstants.avgLifeAPCImmatrue;
		life = GlobalConstants.sampleNormal(avgLife);
		
		moveInterval = GlobalConstants.moveIntervalAPC;
		
		probEnterLymph = 0;
		probEnterThymus = 0;
		probExit = 0;
		
		//do not proliferate
		proliferateCount = 0;
		
		setColor(GlobalConstants.colorAPCImmature);
		
		double r = Model.getUniformDoubleFromTo(0.0,1.0); 
		if (r < GlobalConstants.frqSusceptibleAPC) {
			CD4Positive = true;
		}else {
			CD4Positive = false;
		}
		
		infected = false;
		bearingVirus = null;
		reactivationRate = GlobalConstants.reactivationRateAPC;
		state = AgentState.IMMATURE;
	}
	
	public void statesAndInteractions(){
		if(!alive) return;
		if(CD4Positive) {
			if(infected) {
				//reactivate
				double r = Model.getUniformDoubleFromTo(0, 1);
				if(r < reactivationRate){
					bearingVirus.reactivate(getMyOrgan(), x, y);
					agentDie();
				}
			}
			if(Organ2D != null) {
				if(infected) { 
					//activate CD8 memory
					activateMatchingCD8Memory();
					//search for CD8 effector and get killed
					double r2 = Model.getUniformDoubleFromTo(0, 1);
					if(r2 < probKilledByMatchingCD8TEffector()) {
						agentDie();
					}
				}else {
					Virus v = getALocalVirus();
					if (v != null) {
						getInfected(v);
					}
				}
			}
		}
		if(Organ2D!=null){
			switch (state){
			case IMMATURE:
				//pick up a virus and mature
				Virus v = getALocalVirus();
				if(v != null){
					presentStrain = v.myStrain;
					changeState(AgentState.MATURE);
				}
				break;
			default://MATURE
				activateNeighborCells();
				break;
			}
		}
	}
	
	/**
	 * primes Naive CD4/CD8 T cells;
	 * activate memory CD4 T cells;
	 * activate SLPCs
	 */
	public void activateNeighborCells(){
		ArrayList<Object> cList = Organ2D.cellSpace.getMooreNeighborOfType(x, y, 5, Cell.class);
		Iterator<Object> cIter = cList.iterator();
		while(cIter.hasNext()) {
			Object o = cIter.next();
			//if T cells
			if(TCell.class.isInstance(o)){
				if(CD4TCell.class.isInstance(o)){
					CD4TCell c = (CD4TCell)o;
					if(c.isAlive() && c.isMemory() && c.recognizeStrain == presentStrain){
						double r = Model.getUniformDoubleFromTo(0, 1);
						if(r < GlobalConstants.probAPCPrimeCD4T){
							c.activate();
							//System.out.println("CD4 memory PRIMING!");
						}
					}else if (c.isAlive() && c.isNaive() && c.recognizeStrain == presentStrain) {
						c.activate();
						//System.out.println("CD4  PRIMING!");
					}
				}else{ // CD8 T cell
					CD8TCell c = (CD8TCell)o;
					if (c.isAlive() && c.isNaive() && c.recognizeStrain == presentStrain) {
						double r = Model.getUniformDoubleFromTo(0, 1);
						if(r < GlobalConstants.probAPCPrimeCD8T){
							c.activate();
							//System.out.println("CD8 PRIMING!");
						}
					}
				}
			}else if (BCell.class.isInstance(o)){
				BCell c = (BCell)o;
				if(c.isAlive() && c.isSLPC() && c.recognizeStrain == presentStrain){
					double r = Model.getUniformDoubleFromTo(0, 1);
					if(r < GlobalConstants.probAPCActivateSLPC){
						c.SHMSignal = true;
					}
				}
			}else{
				continue;
			}
		}
	}
	
	/**
	 * check if this cell is susceptible;
	 */
	public boolean isSusceptible() {
		boolean susceptible = false;
		if (CD4Positive) {
			if (!infected) {
				susceptible = true;
			}
		}
		return susceptible;
	}
	
	/**
	 * 
	 */
	public void getInfected(Virus v) {
		infected = true;
		bearingVirus = v;
		presentStrain = v.myStrain;
		v.infectHostCell();
	}
	
	public void changeState(AgentState s) {
		state = s;
		switch(s){
			case MATURE:
				avgLife = GlobalConstants.avgLifeAPCMature;
				life = GlobalConstants.sampleNormal(avgLife);
				break;
			default:
				break;
		}
	}
	
	public void matureOnRecruit(int vLoad){
		double r = Model.getUniformDoubleFromTo(0.0,1.0); 
		double p = GlobalConstants.maxMatureFrq * vLoad / (vLoad + GlobalConstants.halfMatureFrqLoad);
		if (r < p) {
			//get a virus from blood
			Virus v = theModel.bloodStream.virusList.get(Model.getUniformIntFromTo(0, vLoad - 1 ));
			presentStrain = v.myStrain;
			changeState(AgentState.MATURE);
		}
	}
}
